﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace Serial
{
    public partial class Form1 : Form
    {
        String serialPortName;

        public Form1()
        {
            InitializeComponent();
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x0219)//检测串口发生改变
            {
                if (m.WParam.ToInt32() == 0x8004)//USB串口拔出
                {
                    string[] ports = System.IO.Ports.SerialPort.GetPortNames();//重获取串口号
                    comboBox_PortNames.Items.Clear();
                    comboBox_PortNames.Items.AddRange(ports);//重获取串口号添加到下拉框中
                    if (button_OpenSerial.Text == "关闭串口")//用户打开过串口
                    {
                        if (!serialPort1.IsOpen)//用户打开的串口被关闭:说明热插拔是用户打开的串口
                        {
                            button_OpenSerial.Text = "打开串口";//恢复打开串口按钮状态
                            serialPort1.Dispose();//serialPort1释放资源
                            comboBox_PortNames.SelectedIndex = comboBox_PortNames.Items.Count > 0 ? 0 : -1;//如果里边有串口默认选择第0个，如果没有默认不选择
                        }
                        else//用户打开的串口没有被关闭:说明热插拔是其他串口
                        {
                            comboBox_PortNames.Text = serialPortName;//显示用户打开的串口号
                        }
                    }
                    else//用户没有打开串口
                    {
                        comboBox_PortNames.SelectedIndex = comboBox_PortNames.Items.Count > 0 ? 0 : -1;//如果里边有串口默认选择第0个，如果没有默认不选择
                    }
                }
                else if (m.WParam.ToInt32() == 0x8000)//USB串口连接上
                {
                    string[] ports = System.IO.Ports.SerialPort.GetPortNames();//重获取串口号
                    comboBox_PortNames.Items.Clear();
                    comboBox_PortNames.Items.AddRange(ports);//重获取串口号添加到下拉框中
                    if (button_OpenSerial.Text == "关闭串口")//用户打开过串口
                    {
                        comboBox_PortNames.Text = serialPortName;//显示用户打开的串口号
                    }
                    else
                    {
                        comboBox_PortNames.SelectedIndex = comboBox_PortNames.Items.Count > 0 ? 0 : -1;//显示获取的第一个串口号
                    }                   
                }
            }
            base.WndProc(ref m);
        }
        /// <字节数组转16进制字符串>
        /// <param name="bytes"></param>
        /// <returns> String 16进制显示形式</returns>
        public static string byteToHexStr(byte[] bytes)
        { 
            string returnStr = "";
            try
            {
                if (bytes != null)
                {
                    for (int i = 0; i < bytes.Length; i++)
                    {
                        returnStr += bytes[i].ToString("X2");
                        returnStr += " ";//两个16进制用空格隔开,方便看数据
                    }
                }
                return returnStr;
            }
            catch (Exception)
            {
                return returnStr;
            }
        }
        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void label1_Click_1(object sender, EventArgs e)
        {

        }

        private void comboBox_BaudRate_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void comboBox_DataBit_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void comboBox_StopBit_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            string[] ports = System.IO.Ports.SerialPort.GetPortNames();//获取所有串口
            comboBox_PortNames.Items.AddRange(ports);//将所有串口添加到串口界面下拉框中
            comboBox_PortNames.SelectedIndex = comboBox_PortNames.Items.Count > 0 ? 0:-1;//如果里边有串口默认选择第0个，如果没有默认不选择

            comboBox_BaudRate.Text = "115200";/*默认波特率:115200*/
            comboBox_StopBit.Text = "1";/*默认停止位:1*/
            comboBox_DataBit.Text = "8";/*默认数据位:8*/
            comboBox_Parity.Text = "None";/*默认奇偶校验位:无*/
        }

        private void button_OpenSerial_Click(object sender, EventArgs e)
        {
            if (button_OpenSerial.Text == "打开串口")
            {
                try
                {
                    serialPort1.PortName = comboBox_PortNames.Text;
                    serialPortName = comboBox_PortNames.Text;
                    serialPort1.BaudRate = int.Parse(comboBox_BaudRate.Text);
                    serialPort1.DataBits = int.Parse(comboBox_DataBit.Text);

                    if (comboBox_StopBit.Text == "1")
                    {
                        serialPort1.StopBits = System.IO.Ports.StopBits.One;
                    }
                    else if (comboBox_StopBit.Text == "1.5")
                    {
                        serialPort1.StopBits = System.IO.Ports.StopBits.OnePointFive;
                    }
                    else if (comboBox_StopBit.Text == "2")
                    {
                        serialPort1.StopBits = System.IO.Ports.StopBits.Two;
                    }

                    if (comboBox_Parity.Text == "None")
                    {
                        serialPort1.Parity = System.IO.Ports.Parity.None;
                    }
                    else if (comboBox_Parity.Text == "Odd")
                    {
                        serialPort1.Parity = System.IO.Ports.Parity.Odd;
                    }
                    else if (comboBox_Parity.Text == "Even")
                    {
                        serialPort1.Parity = System.IO.Ports.Parity.Even;
                    }

                    serialPort1.Open();
                    button_OpenSerial.Text = "关闭串口";
                    MessageBox.Show("打开成功", "提示!");//对话框显示打开成功

                }
                catch (Exception err)
                {
                    MessageBox.Show("打开失败" + err.ToString(), "提示!");//对话框显示打开失败
                }
            }
            else
            {
                try
                {
                 serialPort1.Close();//关闭串口
                }
                catch (Exception)
                { 

                }
                button_OpenSerial.Text = "打开串口";
             }

        }

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            int len = serialPort1.BytesToRead;//获取串口字节数
            byte[] buff = new byte[len];//定义字节数组
            serialPort1.Read(buff, 0, len);//读取串口数据
            string str = Encoding.Default.GetString(buff);//将字节数组转换为字符串
            Invoke((new Action(() => //C# 3.0以后代替委托的新方法
            {
                if (checkBox_Hex.Checked)
                {
                    textBox_receive.AppendText(byteToHexStr(buff) + "\r\n");//将接收到的数据显示在接收框中
                }
                else
                {
                    textBox_receive.AppendText(str + "\r\n");//将接收到的数据显示在接收框中
                }
                //textBox_receive.AppendText(str);//将接收到的数据显示在接收框中

            })));
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void checkBox_Hex_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void button_TextClear_Click(object sender, EventArgs e)
        {
            textBox_receive.Clear();//清除对话框内容
        }

        private void button_send_Click(object sender, EventArgs e)
        {
            string Str = textBox_send.Text.ToString();//获取发送文本框的字符串
            try
            {
                if (Str.Length > 0)
                {
                    if (checkBox_HexSend.Checked)
                    {
                        byte[] byt = strToToHexByte(Str);//将字符串转换为字节数组
                        serialPort1.Write(byt,0,byt.Length);//发送数据
                    }
                    else
                    {
                        serialPort1.Write(Str);//发送数据
                    }
                }

            }
            catch (Exception)
            { }
        }

        private void checkBox_HexSend_CheckedChanged(object sender, EventArgs e)
        {

        }

        /// <字符串转16进制格式,不够自动前面补零>
        /// 
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private static byte[] strToToHexByte(String hexString)
        {
            int i;
            hexString = hexString.Replace(" ", "");//清除空格
            if ((hexString.Length % 2) != 0)//奇数个
            {
                byte[] returnBytes = new byte[(hexString.Length + 1) / 2];
                try
                {
                    for (i = 0; i < (hexString.Length - 1) / 2; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                    returnBytes[returnBytes.Length - 1] = Convert.ToByte(hexString.Substring(hexString.Length - 1, 1).PadLeft(2, '0'), 16);
                }
                catch
                {
                    MessageBox.Show("含有非16进制字符", "提示");
                    return null;
                }
                return returnBytes;
            }
            else
            {
                byte[] returnBytes = new byte[(hexString.Length) / 2];
                try
                {
                    for (i = 0; i < returnBytes.Length; i++)
                    {
                        returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                    }
                }
                catch
                {
                    MessageBox.Show("含有非16进制字符", "提示");
                    return null;
                }
                return returnBytes;
            }
        }

        private void button_send_clear_Click(object sender, EventArgs e)
        {
            textBox_send.Clear();
        }
    }
}
